package com.hhkj.admin.bank.common.component.checker;

import com.hhkj.admin.bank.domain.Bank;
import com.hhkj.admin.bank.domain.BankRule;
import com.hhkj.admin.bank.model.extend.TestQuestionAmountConf;
import com.hhkj.admin.question.common.cont.QuestionTypeEnum;
import com.hhkj.admin.question.domain.Question;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * BankCreateChecker
 *
 * @author ZhengJun
 * @since 2023/6/17 14:46
 */
public class BankCreateChecker {
    /**
     * 校验题目
     *
     * @param bank                      题库信息
     * @param rule                      题目规则
     * @param practiceQuestionGroupList 练习题题目列表
     * @param residueQuestionGroupList  剩余题目组列表
     * @return 题目错误信息列表
     */
    public static <Q extends Question> List<String> checkerAndConfTestAmountIfNotError(
            Bank bank,
            BankRule rule,
            List<Q> practiceQuestionGroupList,
            List<Q> residueQuestionGroupList) {
        Map<String, Integer> testAmountConfMap = rule.getTestAmountConfMap();

        Map<String, Integer> practiceAmountMapByTypeCode = practiceQuestionGroupList.stream()
                .collect(Collectors.groupingBy(Question::getTypeCode,
                        Collectors.collectingAndThen(
                                Collectors.toList(), List::size)));

        Map<String, Integer> residueAmountMapByTypeCode = residueQuestionGroupList.stream()
                .collect(Collectors.groupingBy(Question::getTypeCode,
                        Collectors.collectingAndThen(
                                Collectors.toList(), List::size)));

        BigDecimal practicePercent = rule.getTestPracticePercent();
        BigDecimal residuePercent = rule.getTestResiduePercent();

        Integer totalConfAmount;
        Integer practiceConfAmount;
        Integer residueConfAmount;
        String typeCode;
        Integer practiceQuestionAmount;
        Integer residueQuestionAmount;
        List<String> errorList = new ArrayList<>();
        Map<String, TestQuestionAmountConf> testAmountConfDetailMap = new HashMap<>();
        for (Map.Entry<String, Integer> testAmountConfMapEntry : testAmountConfMap.entrySet()) {
            typeCode = testAmountConfMapEntry.getKey();
            totalConfAmount = testAmountConfMapEntry.getValue();
            practiceConfAmount = calculateQuestionAmount(totalConfAmount, practicePercent, RoundingMode.DOWN);
            residueConfAmount = calculateQuestionAmount(totalConfAmount, residuePercent, RoundingMode.DOWN);
            // 1、如果有题目数量限制的情况
            practiceQuestionAmount = practiceAmountMapByTypeCode.getOrDefault(typeCode, 0);
            residueQuestionAmount = residueAmountMapByTypeCode.getOrDefault(typeCode, 0);
            if (practiceQuestionAmount < practiceConfAmount) {
                errorList.add(QuestionTypeEnum.getNameByCode(typeCode) + "练习题目数量不足");
                continue;
            }
            if (residueQuestionAmount < residueConfAmount) {
                errorList.add(QuestionTypeEnum.getNameByCode(typeCode) + "剩余题目数量不足");
                continue;
            }
            // 如果不相等，一需要判断缺少的一题需要从哪个题库取 ==》 哪个题库类型需要加 1
            if (!totalConfAmount.equals((practiceConfAmount + residueConfAmount))) {
                // 1.1、练习题库数量已经达到上限 优先抽取练习题库信息
                if (practiceConfAmount.equals(practiceQuestionAmount)) {
                    // 查看剩余题库是否支持抽取一道题库
                    if (residueQuestionAmount <= residueConfAmount) {
                        continue;
                    }
                    residueConfAmount++;
                } else if (residueConfAmount.equals(residueQuestionAmount)) {
                    // 查看剩余题库是否支持抽取一道题库
                    practiceConfAmount++;
                }
                // 题目数量够的前提下，剩余题库数量抽取 +1
                else {
                    residueConfAmount++;
                }
            }
            testAmountConfDetailMap.put(typeCode, new TestQuestionAmountConf(typeCode, totalConfAmount, practiceConfAmount, residueConfAmount));
        }
        bank.setTestAmountConfMap(testAmountConfDetailMap);
        return errorList;
    }

    /**
     * 计算题目数量
     *
     * @param percent 半分比
     * @param amount  数量
     * @return 最终题目数量
     */
    private static Integer calculateQuestionAmount(Integer amount, BigDecimal percent, RoundingMode mode) {
        return percent.multiply(BigDecimal.valueOf(amount))
                .divide(BigDecimal.valueOf(100), 0, mode).intValue();
    }
}
